# koa-bodyparser中间件
30 秒速记
koa-bodyparser把请求体解析好挂到ctx.request.body,不用自己读流- 默认只开
json和form,text要手动打开,不支持multipart文件上传 - 默认上限:
jsonLimit和textLimit是1mb,formLimit是56kb,超了返回413 - 格式坏的
JSON会抛400,不支持的类型直接跳过,body是空对象 - 要做
Webhook验签就得拿原始字符串,解析后再JSON.stringify回去对不上签名
koa-bodyparser 干的事就是把上一节手写的那套读流、拼接、解析封装成中间件,结果放在 ctx.request.body 上。 它按 Content-Type 决定怎么解析:application/json 走 JSON 解析,表单走 urlencoded 解析,大小限制、编码、坏数据报错都处理好了。要记住的是它的边界:默认只认 json 和 form,文件上传它不管,要用 koa-body 或 @koa/multer;默认的 formLimit 只有 56kb,表单里有长文本时很容易撞上 413。
理解「koa-bodyparser中间件」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。
工程中还要验证退出码、资源清理和异常输入。属于 middleware 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。
面试官追问
追问 1没注册 koa-bodyparser,直接读 ctx.request.body.username 会怎样?
Koa 本身不解析请求体,ctx.request.body 是 undefined,再读 .username 就抛 TypeError。请求体解析从来都是中间件的活。
追问 2富文本编辑器提交一篇长文章,接口返回 413,怎么回事?
表单类型默认 formLimit 只有 56kb,长文章很容易超。按业务调大,比如 bodyParser({ formLimit: '2mb' }),别图省事直接写个很大的值。
追问 3前端发了一个 text/plain 的请求,ctx.request.body 是空对象,为什么?
默认 enableTypes 只有 ['json', 'form'],其他类型直接跳过不解析。要支持就配 enableTypes: ['json', 'form', 'text']。
追问 4接 GitHub 的 Webhook 要验签,能拿 ctx.request.body 算吗?
不能。签名是对原始字节算的,解析成对象再序列化,空格、键顺序都可能变,签名对不上。要用原始请求体,比如 koa-bodyparser 新版本挂在 ctx.request.rawBody 上的字符串。
追问 5客户端发了一个格式坏掉的 JSON,服务端会怎么响应?
中间件会抛一个 status 为 400 的错误。默认交给 Koa 的错误处理返回 400,也可以传 onerror 自己定响应格式,别让它变成 500。
# koa-bodyparser中间件
# 原理
30 秒速记
- 原理:中间件在业务之前读完
ctx.req流,解析后写到ctx.request.body,再await next() - 按
Content-Type分流:json→JSON.parse,form→querystring解析 - 底层是
co-body+raw-body,负责限长、编码和流读取 - 注意是
ctx.request.body,不是ctx.body,后者是响应体
它的原理很简单:在业务中间件之前把请求流读完、解析好,挂到 ctx.request.body 上,然后 await next() 交给后面的中间件。 这正是 Koa 洋葱模型的典型用法,前置中间件给 ctx 加料,后面的业务代码直接拿结果。解析方式看请求头的 Content-Type,JSON 和表单各走各的解析器,底层用的是 co-body。最常见的混淆是 ctx.request.body 和 ctx.body:前者是请求体,后者是你要返回给客户端的响应体,完全是两个东西。
对于POST请求的处理,koa-bodyparser中间件可以把koa2上下文的formData数据解析到ctx.request.body中
理解「原理」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。
工程中还要验证退出码、资源清理和异常输入。属于 module 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。
面试官追问
追问 1能不能用几行代码说清楚它大概怎么实现的?
核心就是:app.use(async (ctx, next) => { ctx.request.body = await parse(ctx.req); await next() })。parse 里读流、限长、按类型解析,读完再放行。
追问 2ctx.request.body 和 ctx.body 有什么区别?
ctx.request.body 是中间件解析出来的请求数据,ctx.body 是 ctx.response.body 的简写,是要发给客户端的响应。业务代码读前者、写后者。
追问 3为什么 bodyParser 必须注册在路由前面?
Koa 中间件按注册顺序执行,业务路由先跑的话那时候还没人解析过请求体。而且路由处理完通常不调 next(),后面的 bodyParser 根本轮不到执行。
追问 4请求流只能读一次,前面已经有中间件读过了,会怎样?
bodyParser 再读就拿不到数据,可能一直等不到 end 或者得到空结果。所以一个请求只让一个地方去读原始流,要原文就用解析中间件提供的 rawBody。
追问 5前端用浏览器的 FormData 对象提交,ctx.request.body 怎么是空的?
fetch 发 FormData 时 Content-Type 是 multipart/form-data,koa-bodyparser 不处理这种类型。要么前端改用 URLSearchParams 或 JSON,要么后端换 koa-body 并开 multipart: true。
# 安装koa2版本的koa-bodyparser@3中间件
30 秒速记
- 安装:
npm install --save koa-bodyparser@3,@3是早年支持Koa 2的版本线 - 现在新项目直接装
4.x,同样支持Koa 2,API基本兼容 npm 5起install默认就会写进dependencies,--save可以省略- 锁文件要提交,
CI用npm ci按锁文件装,保证各环境版本一致
这一步就是装依赖,指定 @3 是因为当年 koa-bodyparser 的 2.x 对应 Koa 1,3.x 才开始支持 Koa 2 的 async 中间件。 现在已经是 4.x 了,同样跑在 Koa 2 上,用法几乎一样,新项目没必要再锁 @3。--save 是老习惯,npm 5 之后 install 默认就写进 package.json。真正要注意的是团队协作:package-lock.json 要提交,CI 里用 npm ci,不然各人机器上装出来的依赖树可能不一样。
npm install --save koa-bodyparser@3
理解「安装koa2版本的koa-bodyparser@3中间件」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。
工程中还要验证退出码、资源清理和异常输入。属于 middleware 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。
面试官追问
追问 1为什么文档里特意写 @3,直接装最新的不行吗?
写这篇的时候 Koa 2 刚出,koa-bodyparser 最新版还停在给 Koa 1 用的生成器写法,必须指定 3.x 才能配 async 中间件。现在最新的 4.x 本身就支持 Koa 2,直接装最新就行。
追问 2npm install 和 npm ci 有什么区别,CI 里该用哪个?
npm ci 严格按锁文件装,会先删掉 node_modules,锁文件和 package.json 对不上就直接报错。CI 里就该用它,结果可复现。
追问 3本地能跑,CI 报 Cannot find module 'koa-bodyparser',最可能是什么原因?
本地是手动装过但没写进 package.json,或者 package.json 改了没提交。看一下 dependencies 里有没有它,本地删掉 node_modules 重装一遍就能复现。
追问 4装完依赖退出码是 0,能说明中间件已经可用了吗?
只说明包下载成功了。还得在代码里 require 并
